package com.yugao.fintech.antelope.pay.payment.channel.wxpay.paywayV3;

import com.alibaba.fastjson2.JSONObject;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yugao.fintech.antelope.pay.common.service.PaySysConfigService;
import com.yugao.fintech.antelope.pay.constant.PayDataTypeEnum;
import com.yugao.fintech.antelope.pay.constant.PayWayCodeEnum;
import com.yugao.fintech.antelope.pay.model.entity.PayOrder;
import com.yugao.fintech.antelope.pay.model.rqrs.pay.AbstractRS;
import com.yugao.fintech.antelope.pay.payment.channel.wxpay.WxpayPaymentService;
import com.yugao.fintech.antelope.pay.payment.channel.wxpay.utils.WxpayKit;
import com.yugao.fintech.antelope.pay.payment.channel.wxpay.utils.WxpayV3Util;
import com.yugao.fintech.antelope.pay.payment.model.ApiResBuilder;
import com.yugao.fintech.antelope.pay.payment.model.bo.MchAppConfigContext;
import com.yugao.fintech.antelope.pay.payment.model.bo.WxServiceWrapper;
import com.yugao.fintech.antelope.pay.payment.model.rqrs.ChannelRetMsgExt;
import com.yugao.fintech.antelope.pay.payment.model.rqrs.payorder.UnifiedOrderExtRQ;
import com.yugao.fintech.antelope.pay.payment.model.rqrs.payorder.payway.WxNativeOrderRQ;
import com.yugao.fintech.antelope.pay.payment.model.rqrs.payorder.payway.WxNativeOrderRS;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 微信 native支付
 *

 */
@Slf4j
@Service("wxpayPaymentByNativeV3Service") //Service Name需保持全局唯一性
public class WxNative extends WxpayPaymentService {

    @Autowired
    private PaySysConfigService paySysConfigService;

    @Override
    public PayWayCodeEnum getPayWayCode() {
        return PayWayCodeEnum.WX_NATIVE;
    }

    @Override
    public String preCheck(UnifiedOrderExtRQ rq, PayOrder payOrder) {
        return null;
    }

    @Override
    public AbstractRS pay(UnifiedOrderExtRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {
        StopWatch stopWatch = StopWatch.createStarted();
        WxNativeOrderRQ bizRQ = (WxNativeOrderRQ) rq;
        WxServiceWrapper wxServiceWrapper = (WxServiceWrapper) configContextQueryService
                .getClientWrapper(this.getIfCode(), mchAppConfigContext);
        WxPayService wxPayService = wxServiceWrapper.getWxPayService();

        // 构造请求数据
        JSONObject reqJSON = buildV3OrderRequest(wxPayService, payOrder, mchAppConfigContext);

        wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.NATIVE);
        String reqUrl;
        if (mchAppConfigContext.isIsvsubMch()) { // 特约商户
            reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.NATIVE);
        } else {
            reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.NATIVE);
        }

        // 构造函数响应数据
        WxNativeOrderRS res = ApiResBuilder.buildSuccess(WxNativeOrderRS.class);
        ChannelRetMsgExt channelRetMsgExt = new ChannelRetMsgExt();
        res.setChannelRetMsg(channelRetMsgExt);

        // 调起上游接口：
        // 1. 如果抛异常, 则订单状态为: 生成状态, 此时没有查单处理操作。订单将超时关闭
        // 2. 接口调用成功, 后续异常需进行捕捉， 如果 逻辑代码出现异常则需要走完正常流程, 此时订单状态为: 支付中, 需要查单处理。
        try {
            JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
            if (Objects.isNull(resJSON)) {
                log.error("支付响应数据为空");
                throw new BizException("支付失败, 请重新发起支付");
            }
            String codeUrl = resJSON.getString("code_url");
            if (PayDataTypeEnum.CODE_IMG_URL.getCode().equals(bizRQ.getPayDataType())) { //二维码图片地址
                res.setCodeImgUrl(paySysConfigService.getDBApplicationConfig().genScanImgUrl(codeUrl));
            } else {
                res.setCodeUrl(codeUrl);
            }

            // 支付中
            channelRetMsgExt.setChannelState(ChannelRetMsgExt.ChannelState.WAITING);

        } catch (WxPayException e) {
            // 明确失败
            channelRetMsgExt.setChannelState(ChannelRetMsgExt.ChannelState.CONFIRM_FAIL);
            WxpayKit.commonSetErrInfo(channelRetMsgExt, e);
        }
        long time = stopWatch.getTime(TimeUnit.MILLISECONDS);
        log.info("wx native pay end, time: {} ms", time);
        return res;
    }

}
